package guid

import (
	"log"
	"sync"
	"time"
)

type Guid struct {
	serverId      uint16
	sequence      int32
	mx            sync.RWMutex
	lastTimestamp int64
}

func (guid *Guid) NewID() uint64 {
	guid.mx.Lock()
	defer guid.mx.Unlock()

	if guid.serverId > 1 << 10 - 1 {
		log.Println("server_id超出最大值")
		return 0
	}

	timestamp := getMsTimeStamp()
	if timestamp < guid.lastTimestamp {
		log.Println("请调整服务器时间!")
		return 0
	}

	if timestamp == guid.lastTimestamp {
		// 当前毫秒内，则+1
		guid.sequence += 1
		if guid.sequence > 1 << 12 - 1 {
			// 当前毫秒内计数满了，则等待下一毫秒
			guid.sequence = 0
			for {
				timestamp = getMsTimeStamp()
				if timestamp > guid.lastTimestamp {
					break
				}
			}
		}
	} else {
		guid.sequence = 0
	}
	guid.lastTimestamp = timestamp

	//42(毫秒) + 10(serverID) + 12(重复累加)
	return uint64(timestamp<<22) | (uint64(guid.serverId) << 12) | uint64(guid.sequence)
}

func NewGuid(serverId uint16) *Guid {
	return &Guid{
		serverId:      serverId,
		sequence:      0,
		lastTimestamp: -1,
	}
}

//获取当前毫秒级时间戳
func getMsTimeStamp() int64 {
	return time.Now().UnixNano() / 1000 / 1000
}
